﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using SdlDotNet.Core;
using SdlDotNet.Input;
using SdlDotNet.Graphics;
using SdlDotNet.Graphics.Primitives;
using Pokemon;
using Point = System.Drawing.Point;
using Color = System.Drawing.Color;

namespace MapEditor
{
    class Editor
    {
        const int PaletteWidth = 8;

        int TileID;
        float TileScroll;
        float SelLayer;
        bool LastRightClick;
        int LastTileX;
        int LastTileY;
        int ScrollX;
        int ScrollY;
        int LastClickX;
        int LastClickY;
        List<Map> AllTheMaps = new List<Map>();
        Surface Tileset;
        float LastWheelMouse = 0;
        int[,] Selection;

        [STAThread]
        static void Main()
        {
            Editor Pokemon = new Editor();
        }

        public Editor()
        {
            Global.MainSurface = Video.SetVideoMode(480, 320);
            Video.WindowCaption = "Pokedit";
            SdlDotNet.Core.Timer.Initialize();

            Global.Init();
            Input.Init();

            Tileset = new Surface(PaletteWidth * 16, (Global.Tileset.Count / PaletteWidth) * 16);
            int count = 0;
            foreach (Surface tile in Global.Tileset)
            {
                Tileset.Blit(tile, new Point((count % PaletteWidth) * 16, (count / PaletteWidth) * 16));
                count++;
            }

            var stuff = Directory.GetFiles("Maps");

            foreach (string file in Directory.GetFiles("Maps"))
            {
                Map m = new Map();
                m.Load(file);
                AllTheMaps.Add(m);
                m.Draw((int)SelLayer);
            }

            TileID = 0;

            Events.TargetFps = 100;
            Events.Quit += new EventHandler<QuitEventArgs>(this.Quit);
            Events.Tick += new EventHandler<TickEventArgs>(this.Update);
            Events.Run();
        }

        private bool LeftButtonLast = Input.LeftMousePress;

        private void Update(object sender, TickEventArgs args)
        {
            Video.WindowCaption = "Pokedit (FPS: " + Events.Fps + "/" + Events.TargetFps + ")";
            Global.MainSurface.Fill(Color.Black);

            if (Input.KeyDown.Contains(Key.S))
            {
                SaveALLTheMaps();
            }
            if (Input.KeyDown.Contains(Key.LeftArrow))
            {
                ScrollX += 8;
            }
            if (Input.KeyDown.Contains(Key.RightArrow))
            {
                ScrollX -= 8;
            }
            if (Input.KeyDown.Contains(Key.UpArrow))
            {
                ScrollY += 8;
            }
            if (Input.KeyDown.Contains(Key.DownArrow))
            {
                ScrollY -= 8;
            }

            foreach (Map m in AllTheMaps)
            {
                Global.MainSurface.Blit(m.DrawSurface, new Point(ScrollX + m.xPos * 15 * 16, ScrollY + m.yPos * 10 * 16));
            }

            if (Input.MouseX < Global.MainSurface.Width - PaletteWidth * 16)
            {
                SelLayer = Math.Max(0, SelLayer + (Input.WheelMouse - LastWheelMouse) * 5);

                if ((Input.WheelMouse - LastWheelMouse) != 0)
                {
                    foreach (Map m in AllTheMaps)
                    {
                        m.Draw((int)SelLayer);
                    }
                }
            }
            else
            {
                TileScroll = Math.Min(Tileset.Height / 16, Math.Max(0, TileScroll + (Input.WheelMouse - LastWheelMouse) * -5));
            }
            LastWheelMouse = Input.WheelMouse;


            //if (/*Input.LeftMousePress ^ LeftButtonLast &&*/Input.LeftMousePress && ((Input.MouseX - ScrollX) / 16 != LastClickX || (Input.MouseY - ScrollY) / 16 != LastClickY))
            /*{
                float xx = (Input.MouseX - ScrollX) / (15f * 16f);
                float yy = (Input.MouseY - ScrollY) / (10f * 16f);
                int x = (int)Math.Min(Math.Floor(xx), Math.Ceiling(xx));
                int y = (int)Math.Min(Math.Floor(yy), Math.Ceiling(yy));
                

                if (Input.MouseX < Global.MainSurface.Width - PaletteWidth * 16)
                {
                    Map Selected = LocateMap(x, y);

                    if (Selected == null)
                    {
                        if (Input.MouseX - ScrollX < 0 || Input.MouseY - ScrollY < 0)
                        {
                            foreach (Map m in AllTheMaps)
                            {
                                m.xPos += Math.Max(0, -x);
                                m.yPos += Math.Max(0, -y);
                            }

                            ScrollX -= Math.Max(0, -x) * 240;
                            ScrollY -= Math.Max(0, -y) * 160;

                            Map map = new Map();
                            map.xPos = Math.Max(0, x);
                            map.yPos = Math.Max(0, y);
                            AllTheMaps.Add(map);
                            map.Draw((int)SelLayer);
                        }
                        else
                        {
                            Map map = new Map();
                            map.xPos = x;
                            map.yPos = y;
                            AllTheMaps.Add(map);
                            map.Draw((int)SelLayer);
                        }
                    }
                    else
                    {
                        int TileX = (Input.MouseX - ScrollX) / 16 - Selected.xPos * 15;
                        int TileY = (Input.MouseY - ScrollY) / 16 - Selected.yPos * 10;

                        Tile t = new Tile();
                        t.ID = TileID;
                        t.Image = Global.Tileset[TileID];

                        int DiffLayers = (int)SelLayer - Selected.Layers.Count + 1;

                        while (DiffLayers > 0)
                        {
                            Selected.Layers.Add(new Tile[15, 10]);
                            DiffLayers -= 1;
                        }
                        (Selected.Layers[(int)SelLayer])[TileX, TileY] = t;
                        Selected.Draw((int)SelLayer);
                    }
                }
                else
                {
                    int tilex = (Input.MouseX - Global.MainSurface.Width + PaletteWidth * 16) / 16;
                    int tiley = Input.MouseY / 16 + (int)TileScroll;

                    int tile = tiley * PaletteWidth + tilex;
                    TileID = tile;
                }

                LastClickX = (Input.MouseX - ScrollX) / 16;
                LastClickY = (Input.MouseY - ScrollY) / 16;
            }
            */

            if (Input.MouseX < Global.MainSurface.Width - PaletteWidth * 16)
            {
                float TileX = ((Input.MouseX - ScrollX) / 16f );
                float TileY = ((Input.MouseY - ScrollY) / 16f );

                if (Input.LeftMouseDown)
                {
                    if ((int)TileX != LastClickX || (int)TileY != LastClickY)
                    {
                        if (Selection != null)
                        {
                            PutSelection(TileX, TileY);
                        }
                    }

                    LastClickX = (int)TileX;
                    LastClickY = (int)TileY;
                }
            }
            else
            {
                if (Input.RightMousePress != LastRightClick)
                {
                    if (Input.RightMousePress)
                    {
                        LastTileX = (Input.MouseX - Global.MainSurface.Width + PaletteWidth * 16) / 16;
                        LastTileY = Input.MouseY / 16 + (int)TileScroll;
                    }
                    else
                    {
                        int CurrTileX = (Input.MouseX - Global.MainSurface.Width + PaletteWidth * 16) / 16;
                        int CurrTileY = Input.MouseY / 16 + (int)TileScroll;

                        if (CurrTileX - LastTileX >= 0 && CurrTileY - LastTileY >= 0)
                        {
                            Selection = new int[CurrTileX - LastTileX + 1, CurrTileY - LastTileY + 1];

                            for (int x = LastTileX; x <= CurrTileX; x++)
                            {
                                for (int y = LastTileY; y <= CurrTileY; y++)
                                {
                                    int tile = y * PaletteWidth + x;

                                    Selection[x - LastTileX, y - LastTileY] = tile;
                                }
                            }
                        }
                    }
                }

                LastRightClick = Input.RightMousePress;
            }

            Global.MainSurface.Blit(Global.Font.Render("Layer: " + (int)SelLayer, Color.Black), new Point(2, 2));
            Global.MainSurface.Blit(Global.Font.Render("Layer: " + (int)SelLayer, Color.White), new Point(0, 0));

            Global.MainSurface.Blit(Tileset, new Point(Global.MainSurface.Width - PaletteWidth * 16, (int)TileScroll * -16));

            LeftButtonLast = Input.LeftMousePress;
            Global.MainSurface.Update();
        }

        private void Quit(object sender, QuitEventArgs e)
        {
            SaveALLTheMaps();
            Events.QuitApplication();
        }

        private void NewMap(float tilex, float tiley)
        {
            int x = (int)Math.Min(Math.Floor((float)tilex / 15f), Math.Ceiling((float)tilex / 15f));
            int y = (int)Math.Min(Math.Floor((float)tiley / 10f), Math.Ceiling((float)tiley / 10f));

            Map map = new Map();

            if (x < 0 || y < 0)
            {
                foreach (Map m in AllTheMaps)
                {
                    m.xPos += Math.Max(0, -x);
                    m.yPos += Math.Max(0, -y);
                }

                ScrollX -= Math.Max(0, -x) * 240;
                ScrollY -= Math.Max(0, -y) * 160;

                map.xPos = Math.Max(0, x);
                map.yPos = Math.Max(0, y);
            }
            else
            {
                map.xPos = x;
                map.yPos = y;
            }

            AllTheMaps.Add(map);
            map.Draw((int)SelLayer);
        }

        private void PutTile(Map target, float tilex, float tiley, int tileid)
        {
            int TileX = (int)(tilex - target.xPos * 15);
            int TileY = (int)(tiley - target.yPos * 10);

            Tile t = new Tile();
            t.ID = tileid;
            t.Image = Global.Tileset[tileid];

            int DiffLayers = (int)SelLayer - target.Layers.Count + 1;

            while (DiffLayers > 0)
            {
                target.Layers.Add(new Tile[15, 10]);
                DiffLayers -= 1;
            }
            (target.Layers[(int)SelLayer])[TileX, TileY] = t;
        }

        private void PutSelection(float tilex, float tiley)
        {
            Map Target;

            for (int x = 0; x < Selection.GetLength(0); x++)
            {
                for (int y = 0; y < Selection.GetLength(1); y++)
                {
                    Target = LocateTile(tilex + x, tiley + y);

                    if (Target == null)
                    {
                        NewMap(tilex + x, tiley + y);
                    }

                    Target = LocateTile(tilex + x, tiley + y);

                    if (Target != null)
                    {
                        PutTile(Target, tilex + x, tiley + y, Selection[x,y]);
                        Target.Draw((int)SelLayer);
                    }
                }
            }
        }

        private Map LocateTile(float x, float y)
        {
            int MapX = (int)Math.Min(Math.Floor(x / 15f), Math.Ceiling(x / 15f));
            int MapY = (int)Math.Min(Math.Floor(y / 10f), Math.Ceiling(y / 10f));

            return LocateMap(MapX, MapY);
        }

        private Map LocateMap(int x, int y)
        {
            foreach (Map m in AllTheMaps)
            {
                if (m.xPos == x && m.yPos == y)
                {
                    return m;
                }
            }

            return null;
        }

        private void SaveALLTheMaps()
        {
            foreach (string file in Directory.GetFiles("Maps"))
            {
                File.Delete(file);
            }

            foreach (Map m in AllTheMaps)
            {
                string filename = m.Filename;

                /*
                if (String.IsNullOrWhiteSpace(filename))
                {
                    filename = @"Maps/map" + m.xPos + "x" + m.yPos + "y";

                    while (FilenameExists(filename))
                    {
                        filename += "I";
                    }
                }
                */

                filename = @"Maps/map" + m.xPos + "x" + m.yPos + "y";

                StreamWriter writer = File.CreateText(filename + ".pmap");
                writer.Write(m.Unload());
                writer.Close();
            }
        }

        private bool FilenameExists(string filename)
        {
            foreach (Map m in AllTheMaps)
            {
                if (m.Filename == filename)
                {
                    return true;
                }
            }

            return false;
        }
    }
}
